#include "WebsiteCommand.h"



WebsiteCommand::WebsiteCommand(SQLSystem* sql):Command(sql)
{
	
	cmdDelete = new DeleteCommand(sql);
	cmdSelect = new SelectCommand(sql);
	cmdInsert = new InsertCommand(sql);
}

WebsiteCommand::WebsiteCommand()
{
}

WebsiteCommand::~WebsiteCommand(void)
{
}

int WebsiteCommand::execute(const string &str)
{
	return true;
}


//insert website (name, file_name,url, view_date ) VALUES(...)
int WebsiteCommand::insertWebsite(const string &str)
{
	
	string insertStr;
	
	typedef tokenizer<char_separator<char> > token;
	char_separator<char> sep(" ","(),",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	insertStr += "INSERT INTO ";
	++tok_iter;
	if(helper->toUpperString(*tok_iter) != "WEBSITE")
	{
		cout << "WRONG FORMAT";
		return false;
	}
	insertStr += *tok_iter;
	++tok_iter;
	while(tok_iter != tok.end())
	{
		if(helper->toUpperString(*tok_iter) == "VALUES")
			insertStr += " ";
		insertStr += *tok_iter;
		++tok_iter;
	}

	if(cmdInsert->execute(insertStr))
		return true;
	else
		return false;

}

//DELETE WEBSITE NAME/PATH=...
int WebsiteCommand::deleteWebsite(const string &str)
{

	string deleteStr;
	typedef tokenizer<char_separator<char> > token;
	char_separator<char> sep(" ","",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	deleteStr += "DELETE FROM ";
	++tok_iter;
	if(helper->toUpperString(*tok_iter) != "WEBSITE")
	{
		cout << "WRONG FORMAT";
		return false;
	}
	deleteStr += *tok_iter+ " WHERE";
	++tok_iter;
	while(tok_iter != tok.end())
	{
		deleteStr += " "+ *tok_iter;
		++tok_iter;
	}

	if(cmdDelete->execute(deleteStr))
		return true;
	else
		return false;
	
}
// Search website name/url=""
int WebsiteCommand::searchWebsite(const string &str)
{
	string searchStr;
	typedef tokenizer<char_separator<char> > token;
	char_separator<char> sep(" ","",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	searchStr += "SELECT * FROM  WEBSITE WHERE";
	tok_iter++;
	if(helper->toUpperString(*tok_iter) != "WEBSITE")
	{
		cout << "WRONG FORMAT";
		return false;
	}

	++tok_iter;
	cout << "search by : "<< *tok_iter;
	if( helper->toUpperString(*tok_iter) == "CONTENT")
	{

		// Search by content
		
		++tok_iter;
		//search function only support "=" operator
		if(*tok_iter != "=")
		{
			cout << "WRONG OPERATOR" << endl;
			return false;
		}
		++tok_iter;
		//get the content string to search
		string searchContentStr;
		if((*tok_iter)[0] == '\"')
		{
			int i=1;
			while((*tok_iter)[i] != '\"')
			{
				searchContentStr += (*tok_iter)[i];
				++i;
				if(i >= (int)(*tok_iter).size())
				{
					searchContentStr += " "; //add space between two words
					++tok_iter;	//next token to continue merging the string
					i=0;	//set i=0 so in the while condition we check again from the start. when comes to the closing quote i= token's size-1 therefore
							//the while continue and check for condition and fail
					continue;
				}
			}	
		}
		else
		{
			cout << "MISSING DOUBLE QUOTE FOR STRINGS" <<endl;
			return false;
		}
		++tok_iter;
		//after the content string there will be no more element in the search statement
		if(tok_iter != tok.end())
		{
			cout << "REDUNDANT ELEMENT IN STATEMENT" << endl;
			return false;
		}
		Table* t;
		t = sql->getTableByName(constants::website());
		int fileNameCol = t->getColumnIndex(constants::file_name());
		int nameCol = t->getColumnIndex(constants::name());
		vector<Row *> rows= t->getRows();
		string fileName;
		string name;
		Cell *tmpCell;
		Cell *nameCell;
		for( unsigned int i = 0; i< rows.size(); i++)
		{
			tmpCell = rows[i]->getCell(fileNameCol);
			nameCell = rows[i]->getCell(nameCol);
			VarcharCell* vfileCell= dynamic_cast<VarcharCell *>(tmpCell);
			VarcharCell* vNameCell= dynamic_cast<VarcharCell *>(nameCell);
			if(!vfileCell || !vNameCell)
			{
				cout << "Not varchar cell" << endl;
				return false;
			}
			fileName= vfileCell->getData();
			name = vNameCell->getData();
			cout << "Website Name: " << name << endl;
			search(fileName,searchContentStr);
		}
		return true;
			
	}else{
		
		while(tok_iter != tok.end())
		{
			searchStr += " "+ *tok_iter;
			++tok_iter;
		}
		return cmdSelect->execute(searchStr);
	}

	
}

void WebsiteCommand::search(const string &fileName, const string &content)
{
	ifstream inputStream;
	string filePath = constants::data_path() + fileName;
	inputStream.open(filePath.c_str());
	if(inputStream.fail())
	{
		cout << "Cannot open file " << filePath << endl;
		return;
	}
	string line;
	char next;
	int found;
	int lineNum=0;
	while(!inputStream.eof())
	{
		++lineNum;
		line="";
		inputStream.get(next);
		while(!inputStream.eof())
		{
			if(next == '\n')
			{
				//cout << "xuong" << endl;
				break;
			}
			line += next;
			inputStream.get(next);
		}
		found= line.find(content);
		if(found != string::npos)
			cout << "Line " <<lineNum << ": " << line << endl;

	}
	inputStream.close();
	
}
//SORT WEBSITE BY NAME/PATH...
int WebsiteCommand::sort(const string &str)
{
	Table* table;
	SQLSystem* system;
	system= getSystem();
	string sortStr;
	typedef tokenizer<char_separator<char> > token;
	char_separator<char> sep(" ","",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	++tok_iter;
	if(tok_iter == tok.end())
		return false;
	if(helper->toUpperString(*tok_iter) != "WEBSITE")
	{
		cout << "WRONG FORMAT";
		return false;
	}
	table= system->getTableByName(*tok_iter);
	if(!table)
	{
		cout << "Table not found\n";
		return false;
	}
	++tok_iter;
	if(tok_iter == tok.end())
		return false;
	if(helper->toUpperString(*tok_iter) != "BY")
	{
		cout << "WRONG FORMAT";
		return false;
	}
	++tok_iter;
	if(tok_iter == tok.end())
		return false;
	int ColIndex= table->getColumnIndex(*tok_iter);
	vector<Row *> rows= table->getRows();
	vector<int> types= table->getTypes();
	//sort part using insertion sort
	int i,j;
	Row* key;
	for (j = 1; j < (int)rows.size(); j++) 
	{
		  key= rows[j];
		  Cell* currentCell= rows[j]->getCell(ColIndex);
		  for(i = j-1; i>=0 ;i--)
		  {
			  Cell* cell= rows[i]->getCell(ColIndex);
			  if(types[ColIndex] == INT)
			  {
				  IntCell* iCurrentCell= dynamic_cast<IntCell *>(currentCell);
				  IntCell* iCell= dynamic_cast<IntCell *>(cell);
				  int c,curr;
				  c= iCell->getData();
				  curr= iCurrentCell->getData();
				  if(c < curr)
					  break;
					
				  else
				  {
					  table->setRow(i,i+1);
					  rows[i+1]=rows[i];
				  }
			  }
			  else if(types[ColIndex] == VARCHAR)
			  {
				  VarcharCell* vCurrentCell= dynamic_cast<VarcharCell *>(currentCell);
				  VarcharCell* vCell= dynamic_cast<VarcharCell *>(cell);
				  string c,curr;
				  c= vCell->getData();
				  curr= vCurrentCell->getData();
				  cout << "cell: " << c << endl;
				  cout << "current: " << curr << endl;
				  if(c < curr)
					  break;					
				  else
				  {
					  table->setRow(i,i+1);
					  rows[i+1]=rows[i];
				  }
			  }
			  else
			  {
			  }
			  
		  }
		  table->setRow(i+1,key);
		  rows[i+1]=key;
    }
	cout << "Sorting completed." << endl;
	return true;

	

}
